package org.manon.json.meta;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;

import org.manon.json.annotation.JSonMap;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
public final class MetaPropertyMap extends MetaProperty{

	private final Class<?> _keyItem;
	private final Class<?> _valueItem;
	private final Class<?> _mapClass;
	
//	@SuppressWarnings("rawtypes")
//	private final Class<? extends CustomSerializer> _collectionItemSerializer;
	
	private static Class<?> findClassFromGeneric(TypeVariable<Class<?>> variable,String genericName) {
		
		for (TypeVariable<?> classType : variable.getGenericDeclaration().getTypeParameters()) {
			if (genericName.equals(classType.getName())) {
//				System.out.println("---------->" + classType.getName());
//				System.out.println("---------->" + classType.getBounds());
//				System.out.println("---------->" + classType.getBounds().length);
//				System.out.println("---------->" + classType.getBounds()[0]);
			}
		}
		
		throw new RuntimeException();
	}
	
	public MetaPropertyMap(String name, String label, Method method) {
		super(MetaPropertyType.MAP,name, label, method);
		
		if (method.getGenericReturnType() instanceof ParameterizedType) {

			if ( ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[0] instanceof Class) {
				_keyItem = (Class<?>) ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[0];
			} else {
				TypeVariable<Class<?>> variable = (TypeVariable<Class<?>>) ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[0];
				
//				System.out.println("variable -> " + variable);
//				System.out.println("variable -> " + variable.getName());
//				System.out.println("variable -> " + variable.getBounds());
//				System.out.println("variable -> " + variable.getBounds().length);
//				System.out.println("variable -> " + variable.getBounds()[0]);
//				System.out.println("variable -> " + variable.getBounds()[0].getClass());
//				System.out.println("variable -> " + variable.getGenericDeclaration());
//				System.out.println("variable -> " + variable.getGenericDeclaration().getTypeParameters().length);
//
//				findClassFromGeneric(variable,variable.getName());
				
				throw new RuntimeException();
			}
			
			//_keyItem = (Class<?>) ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[0];
			_valueItem = (Class<?>) ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[1];
		} else {
			_keyItem = _valueItem = Object.class;
		}
		
		JSonMap jsonMap = method.getAnnotation(JSonMap.class);
		
		if (jsonMap == null) {
			_mapClass = java.util.HashMap.class;
		} else {
			_mapClass = jsonMap.mapImpl();
		}
		
//		JSonSerializer serializer = method.getAnnotation(JSonSerializer.class);
//		if (serializer != null) {
//			_collectionItemSerializer = serializer.impl();
//		} else {
//			_collectionItemSerializer = null;
//		}
	}

	public Class<?> getKeyItem() {
		return _keyItem;
	}

	public Class<?> getValueItem() {
		return _valueItem;
	}

	public Class<?> getMapClass() {
		return _mapClass;
	}


	/**
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(MetaProperty otherProperty) {
		
		if (otherProperty instanceof MetaPropertyMap) {
			return getLabel().compareTo(otherProperty.getLabel());
		}
		
		if (otherProperty instanceof MetaPropertySingleValue) {
			return 1;
		}
		
		// other property is a association
		return 1;
	}

	@Override
	public String toString() {
		final StringBuilder builder = new StringBuilder(128);
		builder.append("Property Collection : ");
		toString(builder);
//		builder.append(", item=[").append(_collectionItem).append("]");
//		builder.append(", class=[").append(_collectionClass).append("]");
		return builder.toString();
	}
	
	/**
	 * @see org.manon.json.meta.MetaProperty#accept(org.manon.json.meta.MetaPropertyVisitor)
	 */
	@Override
	public void accept(MetaPropertyVisitor visitor) {
		visitor.visit(this);
	}
}